package com.hudson.store.commitlog;


import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MappedFile {
    private File file;
    private RandomAccessFile randomAccessFile;
    private FileChannel fileChannel;
    private MappedByteBuffer mappedByteBuffer;
    private long fileSize;
    private long currentOffset = 0; // 当前写入位置

    public MappedFile(String fileName) {
        this.file = new File(fileName);
        this.fileSize = CommitLogManger.FILE_SIZE;

        try {
            boolean isNewFile = !file.exists();
            if (!file.exists()) {
                file.createNewFile();
            }

            randomAccessFile = new RandomAccessFile(file, "rw");
            fileChannel = randomAccessFile.getChannel();

            // 映射整个文件到内存
            mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);

            if (isNewFile) {
                currentOffset = CommitLogManger.FILE_SIZE * Integer.parseInt(file.getName().substring(0, file.getName().lastIndexOf("."))) + 8;

                mappedByteBuffer.position(0);
                mappedByteBuffer.putLong(currentOffset);
                System.out.println(currentOffset);
            } else {
                // 从文件头读取保存的 offset
                mappedByteBuffer.position(0);
                currentOffset = CommitLogManger.FILE_SIZE * Integer.parseInt(file.getName().substring(0, file.getName().lastIndexOf("."))) + mappedByteBuffer.getLong();
                System.out.println(currentOffset);
            }

        } catch (IOException e) {
            throw new RuntimeException("Failed to map file: " + fileName, e);
        }
    }


    public long asyncWriteByFlush(byte[] data){
        return write(data,false);
    }


    public long syncWriteByFlush(byte[] data){
        return write(data,true);
    }

    /**
     * 写入数据到内存映射文件
     */
    public long write(byte[] data,boolean sync) {
        int totalLength = data.length;
        long returnValue;
        returnValue = currentOffset;
        long currOffset = currentOffset % fileSize;

        mappedByteBuffer.position((int) currOffset);
        mappedByteBuffer.put(data);

        currentOffset += totalLength;

        // 更新文件头部的 offset
        mappedByteBuffer.position(0);
        mappedByteBuffer.putLong(currentOffset);

        if(sync){
            flush();
        }

        return returnValue;
    }

    /**
     * 从指定 offset 读取指定长度的数据
     */
    public synchronized byte[] read(long offset, int size) {
        if (offset + size > fileSize) {
            return null;
        }

        byte[] data = new byte[size];
        mappedByteBuffer.position((int) offset);
        mappedByteBuffer.get(data);
        return data;
    }

    /**
     * 从指定 offset 读取一行（直到换行符）
     */
    public synchronized byte[] readLine(long offset) {
        if (offset >= fileSize) {
            return null;
        }

        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        int bytesRead = 0;
        int lineEndIndex = -1;

        mappedByteBuffer.position((int) offset);
        while (mappedByteBuffer.hasRemaining() && bytesRead < bufferSize) {
            byte b = mappedByteBuffer.get();
            buffer[bytesRead++] = b;
            if (b == '\n') {
                lineEndIndex = bytesRead;
                break;
            }
        }

        if (lineEndIndex != -1) {
            byte[] line = new byte[lineEndIndex - 1]; // 排除 \n
            System.arraycopy(buffer, 0, line, 0, lineEndIndex - 1);
            return line;
        }

        return null; // 没找到完整的一行
    }

    /**
     * 强制刷盘
     */
    public void flush() {
        mappedByteBuffer.force(); // 或使用 force()
    }

    /**
     * 关闭资源
     */
    public void close() throws IOException {
        flush(); // 确保 offset 写入磁盘
        fileChannel.close();
        randomAccessFile.close();
    }

    public boolean isFull(int size) {
        return currentOffset + size >
                CommitLogManger.FILE_SIZE * (Integer.parseInt(file.getName().substring(0, file.getName().lastIndexOf("."))) + 1);
    }

    public String getFileName() {
        return file.getName();
    }

    public long getCurrentOffset() {
        return currentOffset;
    }

    public void asyncWrite(byte[] allData) {

        long currOffset = currentOffset % fileSize;

        mappedByteBuffer.position((int) currOffset);
        mappedByteBuffer.put(allData);

        currentOffset += allData.length;

        // 更新文件头部的 offset
        mappedByteBuffer.position(0);
        mappedByteBuffer.putLong(currentOffset);
    }
}
